package com.linchong.concurrency.chapter9;

import lombok.extern.slf4j.Slf4j;

import java.util.stream.Stream;

/**
 * @Author:linchong
 * @CreateTime:2020-01-09 11:27
 * @Description:生产者-消费者v2.0
 */
@Slf4j
public class ProduceConsumerVersion3 {
	private int i = 0;
	final private Object LOCK = new Object();

	/**
	 * 判断是否有产品可供消费
	 */
	private volatile boolean isProduced = false;

	public void produce() {
		synchronized (LOCK) {
			//if(isProduced){
			while (isProduced) {
				try {
					LOCK.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			i++;
			log.info("Produce:{}", i);
			LOCK.notifyAll();
			isProduced = true;

		}
	}

	public void consume() {
		synchronized (LOCK) {
			//if(!isProduced){
			while (!isProduced) {
				try {
					LOCK.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			log.info("Consume:{}", i);
			LOCK.notifyAll();
			isProduced = false;
		}
	}

	public static void main(String[] args) {
		ProduceConsumerVersion3 pc = new ProduceConsumerVersion3();
		//单个生产者消费者情况
		//singleCondition(pc);

		Stream.of("Produce-1", "Produce-2", "Produce-3")
				.forEach(p ->
						new Thread(p) {
							@Override
							public void run() {
								while (true) {
									pc.produce();
									try {
										Thread.sleep(10);
									} catch (InterruptedException e) {
										e.printStackTrace();
									}
								}
							}
						}.start()
				);

		Stream.of("Consumer-1", "Consumer-2", "Consumer-3")
				.forEach(c ->
						new Thread(c) {
							@Override
							public void run() {
								while (true) {
									pc.consume();
									try {
										Thread.sleep(10);
									} catch (InterruptedException e) {
										e.printStackTrace();
									}
								}
							}
						}.start()
				);

		log.info("使用if时，会出现这种情况：{}生产了一次，消费了两次。\n", "15:58:58.230 [Produce-3] INFO  c.l.c.c.ProduceConsumerVersion3 - Produce:2\n" +
				"15:58:58.230 [Consumer-1] INFO  c.l.c.c.ProduceConsumerVersion3 - Consume:2\n" +
				"15:58:58.230 [Consumer-2] INFO  c.l.c.c.ProduceConsumerVersion3 - Consume:2");
		log.info("换用while循环判断即可,此种情况下，唤醒后就会判断是否满足条件，在去执行，" +
				"而不是在唤醒的地方继续向后执行");

		//如果是多个线程，只允许部分线程启动操作的话，可以根据条件将它们先放到list集合中，之后遍历集合启动
	}


}
